// let name2 = new String("Matt");
// String.prototype.age = 28
// Object.prototype.age = 29
// console.log(typeof name2)
// name2.age = 27
// console.log(name2.age)
// let name1 = '312312'
// console.log(name1.age)


// 迭代器方法
// keys() 返回数组索引的迭代器
// values() 返回数组元素的迭代器
// entries() 返回索引/值队的迭代器
const a = ['foo', 'bar', 'baz', 'qux']

// 因为这些方法都返回迭代器,所以可以将他们的内容通过 Array.from() 直接转化为数组实例
const aKeys = Array.from(a.keys())
const aValues = Array.from(a.values())
const aEntries = Array.from(a.entries())
console.log(aKeys)
console.log(aValues)
console.log(aEntries)

// 使用 ES6 的解构可以非常容易地在循环中拆分键/值对
for (const [idx, element] of a.entries()) {
    console.log(idx)
    console.log(element)
}


Function.prototype.bind1 = function () {
    // 转化数组
    let args =  Array.prototype.slice.call(arguments)
    console.log(args)
    // 获取第一项
    const t = args.shift()
    let self = this
    return function () {
        return self.apply(t, args)
    }
}

const module = {
    x: 42,
    getX: function() {
      return this.x;
    }
  };
  
  const unboundGetX = module.getX;
  console.log(unboundGetX()); // The function gets invoked at the global scope
  // expected output: undefined
  
  const boundGetX = unboundGetX.bind1(module);
  console.log(boundGetX());
  // expected output: 42
  
// 深拷贝
function deepClone(obj) {
    if (typeof obj !== 'object' || obj == null) {
        return obj
    }
    let result = obj instanceof Array.prototype ? [] : {}
    for (let key in obj) {
        if (obj.hasOwnPerporty(key)) {
            result[key] = typeof result[key] === 'object' ? deepClone(obj[key]) : obj[key]
        }
    }
}


// Object.assign() 这个方法接收一个目标对象和一个或多个源对象作为参数，
// 然后将每个源对象中可枚举（Object.propertyIsEnumerable()返回 true）和自有属性（Object.hasOwnProperty() 返回 true）赋值到目标对象
let dest, src, result;

/*
* 简单复制
*/

dest = {}
src  = {id: 'src'};
result = Object.assign(dest, src)

// Object.assign() 修改目标对象，也会返回修改后的目标对象

console.log(dest === result) // true
console.log(dest !== src) // true
console.log(dest) // {id: 'src'}
console.log(result) // {id: 'src'}

/**
 * 多个源对象
 */

dest = {};
result = Object.assign(dest, { a: 'foo' }, { b: 'bar' })
console.log(result) // { a: 'foo', b: 'bar'}

/**
 * 获取函数与设置函数
 */ 

dest = {
    set a(val) {
        console.log(`Invoked dest stter with param ${val}`)
    }
};

src = {
    get a() {
        console.log('Invoked src getter')
        return 'foo'
    }
}

Object.assign(dest, src)
// 调用 src 的获取方法
// 调用 dest 的设置方法并传入参数"foo"
// 因为这里的设置函数不执行赋值操作
// 所以实际上并没有把值转移过来
console.log(dest); // { set a(val) {...} } 


// 对象解构
let person = {
    name: 'Matt',
    age: 18
}

let { name: personName, age: personAge } = person

// 简写
let { name, job } = person 
console.log(name); // Matt
console.log(job); // undefined


// 嵌套解构
// 通过解构来复制对象属性
// let person = {
//     name: 'Matt',
//     age: 27,
//     job: {
//         title: 'software engineer'
//     }
// }
// let personCopy = {}

// ({
//     name: personCopy.name,
//     age: personCopy.age,
//     job: personCopy.job
// } = person)

// 因为一个对象的引用赋值给 personCopy 所以修改 person.job 对象的属性也会影响 personCopy

person.job.title = 'Hacker'
console.log(person);
// { name: 'Matt', age: 27, job: { title: 'Hacker' } }
console.log(personCopy);
// { name: 'Matt', age: 27, job: { title: 'Hacker' } }


// 解构赋值可以使用嵌套结构，以匹配嵌套的属性：
let person = {
    name: 'Matt',
    age: 27,
    job: {
    title: 'Software engineer'
    }
   };
// 声明 title 变量并将 person.job.title 的值赋给它
let { job: { title } = title } = person

// 在外层属性没有定义的情况下不能使用嵌套解构。无论源对象还是目标对象都一样：
// let person = {
//     job: {
//     title: 'Software engineer'
//     }
//    };
//    let personCopy = {};
// ({
//     foo: { bar: personCopy.bar }
// } = person)
// TypeError: Cannot destructure property 'bar' of 'undefined' or 'null'.

// job 在目标对象上是 undefined
// ({
//     job: {
//     title: personCopy.job.title
//     }
//    } = person);
   // TypeError: Cannot set property 'title' of undefined

